home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Applications / MacWT 0.9 / wt Source / gifload.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-10  |  12.1 KB  |  459 lines  |  [TEXT/CWIE]

  1. /*
  2.  * xgifload.c  -  based strongly on...
  3.  *
  4.  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
  5.  *
  6.  * Copyright (c) 1988, 1989 by Patrick J. Naughton
  7.  *
  8.  * Author: Patrick J. Naughton
  9.  * naughton@wind.sun.com
  10.  *
  11.  * Permission to use, copy, modify, and distribute this software and its
  12.  * documentation for any purpose and without fee is hereby granted,
  13.  * provided that the above copyright notice appear in all copies and that
  14.  * both that copyright notice and this permission notice appear in
  15.  * supporting documentation.
  16.  *
  17.  * This file is provided AS IS with no warranties of any kind.  The author
  18.  * shall have no liability with respect to the infringement of copyrights,
  19.  * trade secrets or any patents by this file or any part thereof.  In no
  20.  * event will the author be liable for any lost revenue or profits or
  21.  * other special, indirect and consequential damages.
  22.  *
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29.  
  30. #include "wt.h"
  31. #include "error.h"
  32. #include "wtmem.h"
  33. #include "color.h"
  34. #include "graphfile.h"
  35.  
  36. typedef int  boolean;
  37. typedef unsigned char byte;
  38.  
  39. #define NEXTBYTE      (*ptr++)
  40. #define IMAGESEP      0x2c
  41. #define GRAPHIC_EXT   0xf9
  42. #define PLAINTEXT_EXT 0x01
  43. #define APPLICATION_EXT 0xff
  44. #define COMMENT_EXT   0xfe
  45. #define START_EXTENSION 0x21
  46. #define INTERLACEMASK 0x40
  47. #define COLORMAPMASK  0x80
  48.  
  49. int BitOffset = 0,        /* Bit Offset of next code */
  50.     XC = 0, YC = 0,        /* Output X and Y coords of current pixel */
  51.     Pass = 0,            /* Used by output routine if interlaced pic */
  52.     OutCount = 0,        /* Decompressor output 'stack count' */
  53.     RWidth, RHeight,        /* screen dimensions */
  54.     Width, Height,        /* image dimensions */
  55.     LeftOfs, TopOfs,        /* image offset */
  56.     BitsPerPixel,        /* Bits per pixel, read from GIF header */
  57.     BytesPerScanline,        /* bytes per scanline in output raster */
  58.     ColorMapSize,        /* number of colors */
  59.     Background,            /* background color */
  60.     CodeSize,            /* Code size, read from GIF header */
  61.     InitCodeSize,        /* Starting code size, used during Clear */
  62.     Code,            /* Value returned by ReadCode */
  63.     MaxCode,            /* limiting value for current code size */
  64.     ClearCode,            /* GIF clear code */
  65.     EOFCode,            /* GIF end-of-information code */
  66.     CurCode, OldCode, InCode,    /* Decompressor variables */
  67.     FirstFree,            /* First free code, generated per GIF spec */
  68.     FreeCode,            /* Decompressor, next free slot in hash table*/
  69.     FinChar,            /* Decompressor variable */
  70.     BitMask,            /* AND mask for data size */
  71.     ReadMask;            /* Code AND mask for current code size */
  72.  
  73. boolean Interlace, HasColormap;
  74. boolean Verbose = FALSE;
  75.  
  76. byte *Image;            /* The result array */
  77. byte *RawGIF;            /* The heap array to hold it, raw */
  78. byte *Raster;            /* The raster data stream, unblocked */
  79.  
  80.     /* The hash table used by the decompressor */
  81. short Prefix[4096];
  82. short Suffix[4096];
  83.  
  84.     /* An output array used by the decompressor */
  85. int OutCode[1025];
  86.  
  87.     /* The color map, read from the GIF header */
  88. byte Red[256], Green[256], Blue[256], used[256];
  89. int  numused;
  90.  
  91. char *id87 = "GIF87a";
  92. char *id89 = "GIF89a";
  93.  
  94. int   ReadCode( void );
  95. int   log2( int );
  96. void  AddToPixel( byte );
  97.  
  98.  
  99. Graphic_file *LoadGIF(FILE *fp, char *fname )
  100. {
  101.     Graphic_file    *gfile;
  102.     int                filesize, numcols;
  103.     register unsigned  char ch, ch1;
  104.     register byte    *ptr, *ptr1;
  105.     register int    i;
  106.     short transparency = -1;
  107.  
  108.   BitOffset = 0;
  109.   XC = YC = 0;
  110.   Pass = 0;
  111.   OutCount = 0;
  112.  
  113.   /* find the size of the file */
  114.   fseek(fp, 0L, 2);
  115.   filesize = ftell(fp);
  116.   fseek(fp, 0L, 0);
  117.  
  118.   if (!(ptr = RawGIF = (byte *) malloc(filesize)))
  119.     fatal_error("not enough memory to read gif file");
  120.  
  121.   if (!(Raster = (byte *) malloc(filesize))) {
  122.     free( ptr );
  123.     fatal_error("not enough memory to read gif file");
  124.   }
  125.  
  126.   if (fread(ptr, filesize, 1, fp) != 1)
  127.     fatal_error("GIF data read failed");
  128.   
  129.   if (strncmp((char *) ptr, id87, 6))
  130.        if (strncmp((char *) ptr, id89, 6))
  131.            fatal_error("not a GIF file");
  132.  
  133.   ptr += 6;
  134.  
  135. /* Get variables from the GIF screen descriptor */
  136.  
  137.   ch           = NEXTBYTE;
  138.   RWidth       = ch + 0x100 * NEXTBYTE; /* screen dimensions... not used. */
  139.   ch           = NEXTBYTE;
  140.   RHeight      = ch + 0x100 * NEXTBYTE;
  141.  
  142.   if (Verbose)
  143.     fprintf(stderr, "screen dims: %dx%d.\n", RWidth, RHeight);
  144.  
  145.   ch           = NEXTBYTE;
  146.   HasColormap  = ((ch & COLORMAPMASK) ? TRUE : FALSE);
  147.  
  148.   BitsPerPixel = (ch & 7) + 1;
  149.   numcols      = ColorMapSize = 1 << BitsPerPixel;
  150.   BitMask      = ColorMapSize - 1;
  151.  
  152.   Background   = NEXTBYTE;        /* background color... not used. */
  153.   
  154.   if (NEXTBYTE)        /* supposed to be NULL */
  155.     fatal_error("corrupt GIF file (bad screen descriptor)");
  156.  
  157. /* Read in global colormap. */
  158.  
  159.   if (HasColormap) {
  160.     if (Verbose)
  161.       fprintf(stderr, "%s is %dx%d, %d bits per pixel, (%d colors).\n",
  162.           fname, RWidth,RHeight,BitsPerPixel, ColorMapSize);
  163.  
  164.     for (i = 0; i < ColorMapSize; i++) {
  165.       Red[i]   = NEXTBYTE;
  166.       Green[i] = NEXTBYTE;
  167.       Blue[i]  = NEXTBYTE;
  168.       used[i]  = 0;
  169.     }
  170.  
  171.     numused = 0;
  172.   } /* else no colormap in GIF file */
  173.  
  174.   /* look for image separator */
  175.  
  176.   for (ch = NEXTBYTE ; ch != IMAGESEP ; ch = NEXTBYTE) {
  177.       i = ch;
  178.       fprintf(stderr, "EXTENSION CHARACTER: %x\n", i);
  179.       if (ch != START_EXTENSION)
  180.           fatal_error("corrupt GIF89a file");
  181.  
  182.       /* handle image extensions */
  183.       switch (ch = NEXTBYTE) {
  184.         case GRAPHIC_EXT:
  185.           ch = NEXTBYTE;
  186.           if (ptr[0] & 0x1) {
  187.               transparency = ptr[3];   /* transparent color index */
  188.               fprintf(stderr, "transparency index: %i\n", transparency);
  189.           }
  190.           ptr += ch;
  191.           break;
  192.         case PLAINTEXT_EXT:
  193.           break;
  194.         case APPLICATION_EXT:
  195.           break;
  196.         case COMMENT_EXT:
  197.           break;
  198.         default:
  199.           fatal_error("invalid GIF89 extension");
  200.       }
  201.  
  202.       while ((ch = NEXTBYTE))
  203.           ptr += ch;
  204.   }
  205.  
  206. /* Now read in values from the image descriptor */
  207.  
  208.   ch        = NEXTBYTE;
  209.   LeftOfs   = ch + 0x100 * NEXTBYTE;
  210.   ch        = NEXTBYTE;
  211.   TopOfs    = ch + 0x100 * NEXTBYTE;
  212.   ch        = NEXTBYTE;
  213.   Width     = ch + 0x100 * NEXTBYTE;
  214.   ch        = NEXTBYTE;
  215.   Height    = ch + 0x100 * NEXTBYTE;
  216.   Interlace = ((NEXTBYTE & INTERLACEMASK) ? TRUE : FALSE);
  217.  
  218.   if (Verbose)
  219.     fprintf(stderr, "Reading a %d by %d %sinterlaced image...",
  220.         Width, Height, (Interlace) ? "" : "non-");
  221.  
  222.   gfile = new_graphic_file();
  223.   gfile->palette = (RGBcolor *)wtmalloc(sizeof(RGBcolor) * ColorMapSize);
  224.   for (i = 0; i < ColorMapSize; i++) {
  225.        gfile->palette[i].red = Red[i];
  226.        gfile->palette[i].green = Green[i];
  227.        gfile->palette[i].blue = Blue[i];
  228.   }
  229.   gfile->bitmap = (unsigned char *)wtmalloc(Width * Height);
  230.   gfile->type = gfPaletted;
  231.   gfile->width = Width;
  232.   gfile->height = Height;
  233.   gfile->transparent_entry = transparency;
  234.  
  235. /* Note that I ignore the possible existence of a local color map.
  236.  * I'm told there aren't many files around that use them, and the spec
  237.  * says it's defined for future use.  This could lead to an error
  238.  * reading some files. 
  239.  */
  240.  
  241. /* Start reading the raster data. First we get the intial code size
  242.  * and compute decompressor constant values, based on this code size.
  243.  */
  244.  
  245.     CodeSize  = NEXTBYTE;
  246.     ClearCode = (1 << CodeSize);
  247.     EOFCode   = ClearCode + 1;
  248.     FreeCode  = FirstFree = ClearCode + 2;
  249.  
  250. /* The GIF spec has it that the code size is the code size used to
  251.  * compute the above values is the code size given in the file, but the
  252.  * code size used in compression/decompression is the code size given in
  253.  * the file plus one. (thus the ++).
  254.  */
  255.  
  256.     CodeSize++;
  257.     InitCodeSize = CodeSize;
  258.     MaxCode      = (1 << CodeSize);
  259.     ReadMask     = MaxCode - 1;
  260.  
  261. /* Read the raster data.  Here we just transpose it from the GIF array
  262.  * to the Raster array, turning it from a series of blocks into one long
  263.  * data stream, which makes life much easier for ReadCode().
  264.  */
  265.  
  266.     ptr1 = Raster;
  267.     do {
  268.     ch = ch1 = NEXTBYTE;
  269.     while (ch--) *ptr1++ = NEXTBYTE;
  270.     if ((ptr1 - Raster) > filesize)
  271.         fatal_error("corrupt GIF file (unblock)");
  272.     } while(ch1);
  273.  
  274.     free(RawGIF);        /* We're done with the raw data now... */
  275.  
  276.     if (Verbose) {
  277.     fprintf(stderr, "done.\n");
  278.     fprintf(stderr, "Decompressing...");
  279.     }
  280.  
  281.     Image               = gfile->bitmap;
  282.     BytesPerScanline    = Width;
  283.  
  284.  
  285. /* Decompress the file, continuing until you see the GIF EOF code.
  286.  * One obvious enhancement is to add checking for corrupt files here.
  287.  */
  288.  
  289.     Code = ReadCode();
  290.     while (Code != EOFCode) {
  291.  
  292. /* Clear code sets everything back to its initial value, then reads the
  293.  * immediately subsequent code as uncompressed data.
  294.  */
  295.  
  296.     if (Code == ClearCode) {
  297.         CodeSize = InitCodeSize;
  298.         MaxCode  = (1 << CodeSize);
  299.         ReadMask = MaxCode - 1;
  300.         FreeCode = FirstFree;
  301.         CurCode  = OldCode = Code = ReadCode();
  302.         FinChar  = CurCode & BitMask;
  303.         AddToPixel(FinChar);
  304.     }
  305.     else {
  306.  
  307. /* If not a clear code, then must be data: save same as CurCode and InCode */
  308.  
  309.         CurCode = InCode = Code;
  310.  
  311. /* If greater or equal to FreeCode, not in the hash table yet;
  312.  * repeat the last character decoded
  313.  */
  314.  
  315.         if (CurCode >= FreeCode) {
  316.         CurCode = OldCode;
  317.         OutCode[OutCount++] = FinChar;
  318.         }
  319.  
  320. /* Unless this code is raw data, pursue the chain pointed to by CurCode
  321.  * through the hash table to its end; each code in the chain puts its
  322.  * associated output code on the output queue.
  323.  */
  324.  
  325.         while (CurCode > BitMask) {
  326.         if (OutCount > 1024) {
  327.             fprintf(stderr,"\nCorrupt GIF file (OutCount)!\n");
  328.                     fatal_error("_exit(%d) called", -1);
  329.                     }
  330.         OutCode[OutCount++] = Suffix[CurCode];
  331.         CurCode = Prefix[CurCode];
  332.         }
  333.  
  334. /* The last code in the chain is treated as raw data. */
  335.  
  336.         FinChar             = CurCode & BitMask;
  337.         OutCode[OutCount++] = FinChar;
  338.  
  339. /* Now we put the data out to the Output routine.
  340.  * It's been stacked LIFO, so deal with it that way...
  341.  */
  342.  
  343.         for (i = OutCount - 1; i >= 0; i--)
  344.         AddToPixel(OutCode[i]);
  345.         OutCount = 0;
  346.  
  347. /* Build the hash table on-the-fly. No table is stored in the file. */
  348.  
  349.         Prefix[FreeCode] = OldCode;
  350.         Suffix[FreeCode] = FinChar;
  351.         OldCode          = InCode;
  352.  
  353. /* Point to the next slot in the table.  If we exceed the current
  354.  * MaxCode value, increment the code size unless it's already 12.  If it
  355.  * is, do nothing: the next code decompressed better be CLEAR
  356.  */
  357.  
  358.         FreeCode++;
  359.         if (FreeCode >= MaxCode) {
  360.         if (CodeSize < 12) {
  361.             CodeSize++;
  362.             MaxCode *= 2;
  363.             ReadMask = (1 << CodeSize) - 1;
  364.         }
  365.         }
  366.     }
  367.     Code = ReadCode();
  368.     }
  369.  
  370.     free(Raster);
  371.  
  372.     if (Verbose)
  373.     fprintf(stderr, "done.\n");
  374.     //else
  375.         //fprintf(stderr,"(of which %d are used)\n",numused);
  376.  
  377.  
  378.   return gfile;
  379. }
  380.  
  381.  
  382. /* Fetch the next code from the raster data stream.  The codes can be
  383.  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  384.  * maintain our location in the Raster array as a BIT Offset.  We compute
  385.  * the byte Offset into the raster array by dividing this by 8, pick up
  386.  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  387.  * bring the desired code to the bottom, then mask it off and return it. 
  388.  */
  389. int
  390. ReadCode( void )
  391. {
  392.     int RawCode, ByteOffset;
  393.  
  394.     ByteOffset = BitOffset / 8;
  395.     RawCode    = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
  396.  
  397.     if (CodeSize >= 8)
  398.     RawCode += (0x10000 * Raster[ByteOffset + 2]);
  399.  
  400.     RawCode  >>= (BitOffset % 8);
  401.     BitOffset += CodeSize;
  402.  
  403.     return(RawCode & ReadMask);
  404. }
  405.  
  406. void
  407. AddToPixel(byte Index)
  408. {
  409.     if (YC<Height)
  410.         *(Image + YC * BytesPerScanline + XC) = Index;
  411.  
  412.     if (!used[Index]) { used[Index]=1;  numused++; }
  413.  
  414. /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  415.  
  416.     if (++XC == Width) {
  417.  
  418. /* If a non-interlaced picture, just increment YC to the next scan line. 
  419.  * If it's interlaced, deal with the interlace as described in the GIF
  420.  * spec.  Put the decoded scan line out to the screen if we haven't gone
  421.  * past the bottom of it
  422.  */
  423.  
  424.     XC = 0;
  425.     if (!Interlace) YC++;
  426.     else {
  427.         switch (Pass) {
  428.         case 0:
  429.             YC += 8;
  430.             if (YC >= Height) {
  431.             Pass++;
  432.             YC = 4;
  433.             }
  434.         break;
  435.         case 1:
  436.             YC += 8;
  437.             if (YC >= Height) {
  438.             Pass++;
  439.             YC = 2;
  440.             }
  441.         break;
  442.         case 2:
  443.             YC += 4;
  444.             if (YC >= Height) {
  445.             Pass++;
  446.             YC = 1;
  447.             }
  448.         break;
  449.         case 3:
  450.             YC += 2;
  451.         break;
  452.         default:
  453.         break;
  454.         }
  455.     }
  456.     }
  457. }
  458.  
  459.